using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace OpenComposite.Mapper
{
	public class XsltDocument : XmlDocument
	{
		#region Initialization

		public XsltDocument()
			: base()
		{
			init();

			_slSourcePrefixNamespace = new SortedList<string, string>();
			//_slSourcePrefixNamespace.Add(this.SourcePrefix, this.SourceSchemaNamespace);
			_slTargetPrefixNamespace = new SortedList<string, string>();
			//_slTargetPrefixNamespace.Add(this.TargetPrefix, this.TargetSchemaNamespace);

			this.AddSourceNamespace(this.SourcePrefix, this.SourceSchemaNamespace);
			this.AddTargetNamespace(this.TargetPrefix, this.TargetSchemaNamespace);
		}
		public XsltDocument(string sourcePrefix, string sourceNamespace,
							string targetPrefix, string targetNamespace)
			: base()
		{
			_sPrefixSource = sourcePrefix;
			_sPrefixTarget = targetPrefix;

			init();

			this.SourceSchemaNamespace = sourceNamespace;
			this.TargetSchemaNamespace = targetNamespace;

			_slSourcePrefixNamespace = new SortedList<string, string>();
			//_slSourcePrefixNamespace.Add(this.SourcePrefix, this.SourceSchemaNamespace);
			_slTargetPrefixNamespace = new SortedList<string, string>();
			//_slTargetPrefixNamespace.Add(this.TargetPrefix, this.TargetSchemaNamespace);

			this.AddSourceNamespace(this.SourcePrefix, this.SourceSchemaNamespace);
			this.AddTargetNamespace(this.TargetPrefix, this.TargetSchemaNamespace);
		}

		private void init()
		{
			this.AppendChild(this.CreateElement(XsltStatics.XsltPrefix, "stylesheet",
												XsltStatics.XsltNamespace));

			this.XsltVersion = "1.0";

			setRootAttribute("xmlns:" + XsltStatics.XmlSchemaInstancePrefix, XsltStatics.XmlSchemaInstanceNamespace);
			setRootAttribute("xmlns:" + XsltStatics.XmlSchemaPrefix, XsltStatics.XmlSchemaNamespace);

			//this.SourceSchemaNamespace = "http://tempuri.org/source";
			//this.TargetSchemaNamespace = "http://tempuri.org/target";

			//setRootAttribute("exclude-result-prefixes", _sPrefixSource);
		}

		#endregion

		#region Public Members

		#region Properties

		public string XsltVersion
		{
			get { return getRootAttribute("version"); }
			set { setRootAttribute("version", value); }
		}

		public string SourcePrefix
		{
			get { return _sPrefixSource; }
		}
		public string SourceSchemaNamespace
		{
			get
			{
				if ( string.IsNullOrEmpty(_sPrefixSource) ) {
					return getRootAttribute("xmlns");
				} else {
					return getRootAttribute("xmlns:" + _sPrefixSource);
				}
			}
			set
			{
				if ( string.IsNullOrEmpty(_sPrefixSource) ) {
					setRootAttribute("xmlns", value);
				} else {
					setRootAttribute("xmlns:" + _sPrefixSource, value);
				}
			}
		}

		public string TargetPrefix
		{
			get { return _sPrefixTarget; }
		}
		public string TargetSchemaNamespace
		{
			get
			{
				if ( string.IsNullOrEmpty(_sPrefixTarget) ) {
					return getRootAttribute("xmlns");
				} else {
					return getRootAttribute("xmlns:" + _sPrefixTarget);
				}
			}
			set
			{
				if ( string.IsNullOrEmpty(_sPrefixTarget) ) {
					setRootAttribute("xmlns", value);
				} else {
					setRootAttribute("xmlns:" + _sPrefixTarget, value);
				}
			}
		}

		#endregion

		#region Methods

		#region Manage Source Namespaces
		public void AddSourceNamespace(string prefix, string xmlns)
		{
			if ( prefix == null ) prefix = "";
			if ( !_slSourcePrefixNamespace.ContainsKey(prefix) ) {
				_slSourcePrefixNamespace.Add(prefix, xmlns);
				if ( prefix == "" ) {
					setRootAttribute("xmlns", xmlns);
				} else {
					setRootAttribute("xmlns:" + prefix, xmlns);
				}
				string prefixes = "";
				foreach ( string pfx in _slSourcePrefixNamespace.Keys ) {
					if ( prefixes != "" ) prefixes += " ";
					prefixes += pfx;
				}
				setRootAttribute("exclude-result-prefixes", prefixes);
			}
		}
		public string GetSourceNamespace(string prefix)
		{
			return _slSourcePrefixNamespace[prefix];
		}
		public string GetSourcePrefix(string xmlns)
		{
			int index = _slSourcePrefixNamespace.IndexOfValue(xmlns);
			if ( index > -1 ) {
				return _slSourcePrefixNamespace.Keys[index];
			} else {
				return null;
			}
		}
		#endregion

		#region Manage Target Namespaces
		public void AddTargetNamespace(string prefix, string xmlns)
		{
			if ( prefix == null ) prefix = "";
			if ( !_slTargetPrefixNamespace.ContainsKey(prefix) ) {
				_slTargetPrefixNamespace.Add(prefix, xmlns);
				if ( prefix == "" ) {
					setRootAttribute("xmlns", xmlns);
				} else {
					setRootAttribute("xmlns:" + prefix, xmlns);
				}
			}
		}
		public string GetTargetNamespace(string prefix)
		{
			return _slTargetPrefixNamespace[prefix];
		}
		public string GetTargetPrefix(string xmlns)
		{
			int index = _slTargetPrefixNamespace.IndexOfValue(xmlns);
			if ( index > -1 ) {
				return _slTargetPrefixNamespace.Keys[index];
			} else {
				return null;
			}
		}
		#endregion

		//public XmlElement CreateTargetElement(string name)
		//{
		//    return this.CreateElement(this.TargetPrefix, name, this.TargetSchemaNamespace);
		//}
		public XmlElement CreateTargetElement(string prefix, string name, string xmlns)
		{
			this.AddTargetNamespace(prefix, xmlns);
			if ( string.IsNullOrEmpty(name) ) {
				return null;
			} else {
				return this.CreateElement(prefix, name, xmlns);
			}
		}

		public XsltElement CreateXsltElement(string elementName)
		{
			return new XsltElement(elementName, this);
		}

		public XsltForEach CreateXsltForEach(string select)
		{
			return new XsltForEach(select, this);
		}

		public XsltAttribute CreateXsltAttribute(string name, string value)
		{
			XsltAttribute xslta = new XsltAttribute(name, this);
			xslta.InnerText = value;
			return xslta;
		}

		public XsltOutput CreateXsltOutput(string method, Encoding encoding, bool indent)
		{
			XsltOutput xslto = new XsltOutput(this);
			xslto.Method = method;
			xslto.Encoding = encoding;
			xslto.Indent = indent;
			return xslto;
		}

		public XsltTemplate CreateXsltTemplate(string match)
		{
			return new XsltTemplate(match, this);
		}

		public XsltVariable CreateXsltVariable(string name, string select)
		{
			XsltVariable xsltv = new XsltVariable(name, select, this);
			return xsltv;
		}

		public XsltValueOf CreateValueOf()
		{
			return new XsltValueOf(this);
		}
		public XsltValueOf CreateValueOf(string select)
		{
			XsltValueOf xsltv = new XsltValueOf(this);
			xsltv.Select = select;
			return xsltv;
		}

		#endregion

		#endregion

		#region Private Members

		#region Variables

		private string _sPrefixSource = "tns1";
		private string _sPrefixTarget = "tns2";

		private SortedList<string, string> _slSourcePrefixNamespace;
		private SortedList<string, string> _slTargetPrefixNamespace;

		#endregion

		#region Methods

		private void setRootAttribute(string name, string value)
		{
			this.DocumentElement.SetAttribute(name, value);
		}
		private string getRootAttribute(string name)
		{
			return this.DocumentElement.GetAttribute(name);
		}

		#endregion

		#endregion
	}
}
